package org.example.judge_contest.controller;


import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.example.judge_common.annotation.AuthAnnotation;
import org.example.judge_common.entity.PageResult;
import org.example.judge_common.entity.ResponseResult;
import org.example.judge_common.hander.RetrunMsgException;
import org.example.judge_common.rank.AllUserRank;
import org.example.judge_common.util.ExcelUtils;
import org.example.judge_common.util.MyUtils;
import org.example.judge_common.rank.RankList;
import org.example.judge_common.rank.RankUser;
import org.example.judge_contest.service.ContestProblemService;
import org.example.judge_contest.service.ContestRecordService;
import org.example.judge_contest.service.ContestRegisterService;
import org.example.judge_contest.service.ContestService;
import org.example.judge_feign_api.UserClient;
import org.example.judge_pojo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 竞赛榜单（记录表）
 */
@Controller
@Slf4j
@RequestMapping("/record")
@CrossOrigin
public class ContestRecordController {

    @Qualifier("ContestRecordServiceImpl")
    @Autowired
    private ContestRecordService contestRecordService;

    @Qualifier("ContestServiceImpl")
    @Autowired
    private ContestService contestService;

    @Autowired
    private RedisTemplate redisTemplate;
    @Qualifier("ContestRegisterServiceImpl")
    @Autowired
    private ContestRegisterService contestRegisterService;
    @Qualifier("ContestProblemServiceImpl")
    @Autowired
    private ContestProblemService contestProblemService;
    @Autowired
    private UserClient userClient;
    @PostMapping("/detail/{id}")
    @AuthAnnotation({Auth.CLIENT})
    public ResponseResult detail(@PathVariable("id")String recordId){
        ContestRecord byId = contestRecordService.getById(recordId);

        return ResponseResult.success().setData(byId);
    }
    @PostMapping("/submit/{id}")
    @AuthAnnotation({Auth.CLIENT})
    public ResponseResult detailBySubmitId(@PathVariable("id")String submitId){

        ContestRecord one = contestRecordService.getBySubmitId(submitId);
        return ResponseResult.success().setData(one);
    }

    @PutMapping("/update")
    @AuthAnnotation({Auth.ADMINISTRATOR})
    public ResponseResult update(@RequestBody ContestRecord contestRecord){
        contestRecordService.updateById(contestRecord);
        return ResponseResult.success();
    }
    @DeleteMapping("/delete/{id}")
    @AuthAnnotation({Auth.ADMINISTRATOR})
    public ResponseResult deleteById(@PathVariable("id") String recordId){
        contestRecordService.removeById(recordId);
        return ResponseResult.success();
    }


    /**
     * 接受题目提交信息。并记录
     * @param submit
     * @return
     */
    @PostMapping("/send/submit")
    @AuthAnnotation({Auth.ADMINISTRATOR})
    @ResponseBody
    public ResponseResult receiveSubmit(@RequestBody Submit submit){
        System.out.println("begin....");

        ContestRecord one = contestRecordService.getBySubmitId(submit.getId());
        if(one==null)return ResponseResult.success();  //不是竞赛中的题目
        //更新结果信息
        if(submit.getErrorStatus()==0){ //通过
            one.setIsAc(0);

        }else {
            one.setIsAc(1);

        }
//        System.out.println(one);

        Contest contest = contestService.getById(submit.getContestId());  //获取比赛信息
        //判断题目是否已经通过
        ContestRecord firstAc = contestRecordService.getFirstAc(submit.getUserId(), submit.getContestId(), submit.getProblemId());
        System.out.println("判断通过类型....");
        if(firstAc==null&&one.getIsAc()==0){  //表示题目第一次通过
            ContestProblem contestProblem = contestProblemService.getByContestAndProblem(contest.getId(), submit.getProblemId());
            //添加相应用户添加积分。
            try{
                userClient.addRating(contestProblem.getRating(),submit.getUserId());
            }catch (Exception e){
                log.error("用户：{}rating积分：{}添加失败：错误信息：{}",submit.getId(),contestProblem.getRating(),e.getMessage());
            }

            //比赛开始时间
            long start = contest.getStartTime().getTime();
            //提交截止时间
            long end = one.getCreateTime().getTime();
            //目前为止错误提交的次数
            int count = contestRecordService.count(submit.getUserId(), submit.getContestId(), submit.getProblemId());
            one.setSubmitSum(count);
            Integer time = Math.toIntExact(count * 20 * 60 + ((end - start) / 1000));  //罚时
            one.setTime(time);
            //判断是否为一血 ,通过的名次
            Integer acceptProblemSum = contestRecordService.getAcceptProblemRank(submit.getContestId(), submit.getProblemId());
            //ContestRecord fir = contestRecordService.getFirstAc(submit.getContestId(),submit.getProblemId());
            one.setIsFirst(acceptProblemSum);
            //else one.setIsFirst(1);
        }else if(firstAc==null){  //题目未通过且本次错误
            //目前为止错误提交的次数
            int count = contestRecordService.count(submit.getUserId(), submit.getContestId(), submit.getProblemId());
            one.setSubmitSum(count+1);
        }
//        System.out.println(one);
        ContestRecord copyOne = JSON.parseObject(JSON.toJSONString(one), ContestRecord.class);
        boolean flag = false; //标记是否已经找到用户
        //更新榜单
        if(firstAc==null&&contest.getStatus()==1){              //此前题目从未通过，可以更新榜单

            //允许封榜
            // 封榜时间已到
            if(contest.getSealRank() == 0 && System.currentTimeMillis() >= contest.getSealRankTime().getTime()){
                if(copyOne.getIsAc()==0) {
                    System.out.println(copyOne);
                    copyOne.setSubmitSum(copyOne.getSubmitSum() + 1);
                }
                copyOne.setIsAc(-1);
                copyOne.setIsFirst(-1);

            }

            // 获取榜单
            RankList rank = contestRecordService.rank(submit.getContestId(),true);
            if(rank!=null){

                for (RankUser user : rank.getUsers()) {
                    if (user.getUserId().equals(submit.getUserId())) {  //找到对应的用户
//                            System.out.println(user.getRecords()+"=="+submit);
                        for (int i = 0; i < user.getRecords().size(); i++) {
                            ContestRecord record = user.getRecords().get(i);
                            if (record.getProblemId().equals(submit.getProblemId())){  //找到对应的题目
                                flag = true;
                                user.getRecords().set(i,copyOne);
                                break;
                            }
                        }
                        if(copyOne.getIsAc()==0){  //通过题目。且为第一次
                            user.setAc(user.getAc()+1);  //题目数+1
                            user.setTime(user.getTime()+copyOne.getTime()); //罚时修改
                            rank.sort();  //重新排序
                        }
                        break;
                    }
                }
                if(!flag){//未找到用户,重新获取
                    log.debug("未找到用户，重新计算获取榜单");
                    //需要提前更新
                    if(contest.getStatus()==1)one.setStatus(0);  //设置为可用
                    contestRecordService.updateById(one);
                    rank = contestRecordService.rank(submit.getContestId(),false);
                }//加入缓存
                redisTemplate.opsForValue().set(RankList.getRedisKey(submit.getContestId()), JSON.toJSONString(rank),1, TimeUnit.HOURS);

            }



        }

        //更新此次提价内容
        if(flag){ //如果已经提前更新，不需要再次更新
            if(contest.getStatus()==1)one.setStatus(0);  //设置为可用
            contestRecordService.updateById(one);
        }

        return ResponseResult.success();
    }

    /**
     * 获取比赛榜单
     * @param contestId
     * @return
     */
    @PostMapping("/list/{id}")
    @ResponseBody
    public ResponseResult list(@PathVariable("id") String contestId,String isCache, HttpServletRequest request){
        RankList res = null;
        if("false".equals(isCache)) {
            log.info("获取榜单，未使用缓存");
            res = contestRecordService.rank(contestId, false);
        }
        else res = contestRecordService.rank(contestId,true);
        //私密比赛
        if(res.getAuth()==1){
            User loginUser = (User)request.getAttribute("loginUser");
            if (loginUser==null) {
                return ResponseResult.unLogin();
            }
            ContestRegister register = contestRegisterService.getByUserIdAndContestId(loginUser.getId(), contestId);
            if(register==null)return ResponseResult.unAuditor();
            if(register!=null&&register.getStatus()==1)return ResponseResult.info("用户已被拉黑");

        }
        return ResponseResult.success().setData(res);
    }

    /**
     * 导出榜单
     * @param contestId
     * @param request
     * @param response
     */
    @PostMapping("/download/rank/{id}")
//    @AuthAnnotation({Auth.ADMINISTRATOR})
    public void downloadRank(@PathVariable("id") String  contestId, HttpServletRequest request, HttpServletResponse response) throws RetrunMsgException {
        RankList rank = contestRecordService.rank(contestId, true);
        Workbook excel = ExcelUtils.getExcel(rank);
        try {
            String filename = excel.getSheetName(0)+".xlsx";
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//            response.set
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
            excel.write(response.getOutputStream());

        } catch (IOException e) {
            log.error("榜单文件导出失败,IOException:"+e.getMessage());
            throw new RetrunMsgException("榜单导出失败");
        }

    }
    //获取所有题目通过数量
    //所有比赛用户通过题目数量排行榜
    @PostMapping("/accept/rank")
    @ResponseBody
    public ResponseResult getAcceptSum(Integer page,Integer size,String beginTime){

        PageResult<AllUserRank> userRank = contestRecordService.getUserRank(page, size,beginTime);
        return ResponseResult.success().setData(userRank);
    }



    //获取用户的比赛统计
    @PostMapping("/progress")
    @ResponseBody
    public ResponseResult getProgress(String userId,HttpServletRequest request){
        if(MyUtils.isEmpty(userId)){
            User loginUser = (User) request.getAttribute("loginUser");
            if(loginUser==null)return ResponseResult.NotData();
            userId = loginUser.getId();
        }
        Map<String,Object> res = new HashMap<>(4);

        //报名的比赛次数 register
        Integer regis = contestRegisterService.getContestCount(userId);
        //参加的比赛 record
        Integer join = contestRecordService.ContestCount(userId);
        //rating排名
        Object data = userClient.getUserRatingRank(userId).getData();
        res.put("rank",data==null?"暂无":data);
        res.put("registerCount",regis);
        res.put("joinCount",join);
        return ResponseResult.success().setData(res);
    }



}
